<?php
/**
 * 
 * @author bruce
 * @date 2016-07-17
 * 
 * 使用方法 eg:
 * $dist = DistrictDicUtils::getInstance( $this->di );
 * $result = $dist->getDistrictsFromID( $areaId );
 * @return object( 省/市/区  和  当前所取的级别  )
 */
namespace libraries;
use apps\mobile\models\fzqDistrictDic;
use Phalcon\Mvc\Model\Resultset;
!defined( 'APP_ROOT' ) && exit( 'Direct Access Deny!' );

class DistrictDicUtils implements \Phalcon\DI\InjectionAwareInterface
{
	static private $_instance = null;
	
	const DISTRICTS_NAME = 'h_district_name';
	const DISTRICTS_ID = 'h_district_id';
	const DISTRICT_CHILDREN = 'h_district_children';
	
	private $_di = null;
	/* (non-PHPdoc)
	 * @see \Phalcon\Di\InjectionAwareInterface::setDI()
	 */
	public function setDI(\Phalcon\DiInterface $dependencyInjector) {
		// TODO Auto-generated method stub
		$this->_di = $dependencyInjector;
	}

	/* (non-PHPdoc)
	 * @see \Phalcon\Di\InjectionAwareInterface::getDI()
	 */
	public function getDI() {
		// TODO Auto-generated method stub
		return $this->_di;
	}

	private function __construct( $di )
	{
       $this->_di = $di;
	}
	
	static public function getInstance( $di )
	{
		if( is_null( self::$_instance ))
		{
			self::$_instance = new DistrictDicUtils( $di );
		}	
		
		return self::$_instance;
	} 
	
	/**
	 * 初始化缓存 系统中只需进行一次
	 */
	public function initCacheData()
	{
		if( !$this->_di->get('nredis')->hGet( $this->DISTRICTS_ID, '1') )
		{//已初始化
			return;
		}
		
		$arrRet = fzqDistrictDic::find( array('hydration' => Resultset::HYDRATE_ARRAYS ));
		
		foreach( $arrRet as $rec )
		{
			$this->_di->get('nredis')->hSetNx( self::DISTRICTS_ID, $rec['id'], json_encode( $rec ) );
			$this->_di->get('nredis')->hSetNx( self::DISTRICTS_NAME, $rec['name'], json_encode( $rec ) );
		}	
	}
	
	/**
	 * 通过ID取区域的子区域
	 * @param number $id
	 * @return mixed|multitype:|NULL
	 */
	public function getChildrenFromID( $id = 0 )
	{
		if( $cacheContent = $this->_di->get('nredis')->hGet( self::DISTRICT_CHILDREN, $id ) )
		{
			return json_decode( $cacheContent );
		}
		
		$arrRet = fzqDistrictDic::find( array( 'conditions' => 'upid=?1', 
				'bind' => array( 1 => $id ), 
				'hydration' => Resultset::HYDRATE_ARRAYS ));

		if( $arrRet->count() )
		{
			$this->_di->get('nredis')->hSet( self::DISTRICT_CHILDREN, $id, json_encode( $arrRet->toArray() ) );
			return $arrRet->toArray();
		}
		return null;
	}
	
	/**
	 * 通过区域名取子区域
	 * @param string $strName
	 * @return mixed|multitype:|NULL
	 */
	public function getChildrenFromName( $strName = null )
	{
		$jsonDist = $this->getSingleDistrFromName( $strName );

		if( $cacheContent = $this->_di->get('nredis')->hGet( self::DISTRICT_CHILDREN, $jsonDist->id ) )
		{
			return json_decode( $cacheContent );
		}
		
		if( $jsonDist )
		{
			$arrRet = fzqDistrictDic::find( array( 'conditions' => 'upid=?1', 
					'bind' => array( 1 => $jsonDist->id ), 
			));
			
			if( $arrRet->count() )
			{
				$this->_di->get('nredis')->hSet( self::DISTRICT_CHILDREN, $jsonDist->id, json_encode( $arrRet->toArray() ) );
				return $arrRet->toArray();
			}
		}
		
		return null;
	}
	
	/**
	 * 通过ID取兄弟
	 */
	public function getSiblingsFromID( $id )
	{
		$jsonDist = $this->getSingleDistrFromID( $id );
		
		if( !$jsonDist )
		{
			return NULL;
		}
		
		return $this->getChildrenFromID( $jsonDist->upid );
	}
	
	/**
	 * 通过名字取兄弟
	 */
	public function getSiblingsFromName( $strName )
	{
		$jsonDist = $this->getSingleDistrFromName( $strName );
		if( !$jsonDist )
		{
			return NULL;
		}
		
		return $this->getChildrenFromID( $jsonDist->upid );
	}
	
	/**
	 * 取单个区域信息
	 * @param unknown $strName
	 * @return mixed|NULL
	 */
	public function getSingleDistrFromName( $strName )
	{
		$obj = $this->_di->get('nredis')->hGet( self::DISTRICTS_NAME, $strName );
		
		if( $obj )
		{
			return json_decode( $obj );
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * 取单个区域信息
	 * @param unknown $strID
	 * @return mixed|NULL
	 */
	public function getSingleDistrFromID( $strID )
	{
		$obj = $this->_di->get('nredis')->hGet( self::DISTRICTS_ID, $strID );
		
		if( $obj )
		{
			return json_decode( $obj );
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * 取$id代表的区域和其所有祖先区域
	 * @param unknown $strName
	 * @return mixed
	 */
	public function getDistrictsFromName( $strName )
	{
		$strName = '"' . $strName . '"' ;
		$strDistsName = '"' . self::DISTRICTS_NAME . '"';
		$strDistrict = '"' . self::DISTRICTS_ID . '"';
		
		$script = <<<EOT
			local item = redis.call( 'hGet', $strDistsName, $strName );
			if item == nil then
				return nil;
			end
					
			local jsonItem = cjson.decode( item );
			local res = {};
			local level = 0;
			while true do
				level = level + 1;
				if( jsonItem['level'] == "1" ) then
					res['level' .. level] = jsonItem;
				
					res['level'] = level;
					return cjson.encode( res );	
				else
					res['level' .. level] = jsonItem;
					item = redis.call( 'hGet', 'h_district_id', jsonItem['upid'] );
					if item == nil then
						return nil;
					end
					jsonItem = cjson.decode( item );
				end
			end
EOT;
		
		
		$obj = json_decode( $this->_di->get('nredis')->eval( $script ));
		
		return $obj;
	}
	
	/**
	 * 使用方法
	 */
	public function test()
	{
// 		$dis = DistrictDicUtils::getInstance();
// 		$dis->setDI( $this->di );
		echo $this->_di->get('utest')->run( preg_match( "/海淀区/", var_export( $this->getChildrenFromID( 1 ), true ) ), true, 'getChildrenFromID(1)' );
		echo $this->_di->get('utest')->run( preg_match( "/海淀区/", var_export( $this->getChildrenFromName( '北京市' ), true ) ), true, "getChildrenFromID('北京市')" );
		echo $this->_di->get('utest')->run( preg_match( "/广东省/", var_export( $this->getDistrictsFromID( 300 ), true ) ), true, "getDistrictsFromID( 300 )" );
		echo $this->_di->get('utest')->run( preg_match( "/广东省/", var_export( $this->getDistrictsFromName( '梅州市' ), true ) ), true, "getDistrictsFromName( '梅州市' )" );
		echo $this->_di->get('utest')->run( preg_match( "/合肥市/", var_export( $this->getSiblingsFromID( 200 ), true ) ), true, "getSiblingsFromID( 200 )" );
		echo $this->_di->get('utest')->run( preg_match( "/合肥市/", var_export( $this->getSiblingsFromName( '亳州市' ), true ) ), true, "getSiblingsFromName( '亳州市' )" );
		echo $this->_di->get('utest')->run( preg_match( "/亳州市/", var_export( $this->getSingleDistrFromID( 200 ), true ) ), true, "getSingleDistrFromID( 200 )" );
		echo $this->_di->get('utest')->run( preg_match( "/200/", var_export( $this->getSingleDistrFromName( '亳州市' ), true ) ), true, "getSingleDistrFromName( '亳州市' )" );
	}
	
	/**
	 * 取$id代表的区域和其所有祖先区域
	 * @param number $id
	 * @return mixed
	 */
	public function getDistrictsFromID( $id = 0 )
	{
		$strDistrict = '"' . self::DISTRICTS_ID . '"';
		
		$script = <<<EOT
		local item = redis.call( 'hGet', $strDistrict, $id );
		if item == nil then
			return nil;
		end
		local jsonItem = cjson.decode( item );
		local res = {};
		local level = 0;
		while true do
				level = level + 1;
				if( jsonItem['level'] == "1" ) then
					res['level' .. level] = jsonItem;
		
					res['level'] = level;
					return cjson.encode( res );
				else
					res['level' .. level] = jsonItem;
					item = redis.call( 'hGet', $strDistrict, jsonItem['upid'] );
					if item == nil then 
						return nil;
					end
					jsonItem = cjson.decode( item );
				end
		end
EOT;
		$obj = json_decode( $this->_di->get('nredis')->eval( $script ));
		
		return $obj;
	}	
}